package com.bp.scoringgun.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bp.scoringgun.entity.Contri;
import com.bp.scoringgun.entity.Org;
import com.bp.scoringgun.entity.User;
import com.bp.scoringgun.entity.UserOrg;
import com.bp.scoringgun.service.ContriService;
import com.bp.scoringgun.service.OrgService;
import com.bp.scoringgun.service.UserOrgService;
import com.bp.scoringgun.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class PredictionServiceImpl {

    @Autowired
    private UserService userService;

    @Autowired
    private ContriService contriService;

    @Autowired
    private OrgService orgService;

    @Autowired
    private UserOrgService userOrgService;

    public void predictNation() {
        // Step 1: 获取 nation 为空的用户
        List<User> usersWithNoNation = userService.list(
                new QueryWrapper<User>()
                        .and(wrapper -> wrapper.isNull("nation").or().eq("nation", ""))
        );

        // Step 2: 构建项目和组织的数据，以便计算分数
        Map<Long, String> userNations = getUserNations();  // 获取 userId -> nation 映射
        Map<Long, String> orgLocations = getOrgLocations(); // 获取 orgId -> location 映射

        // Step 3: 遍历每个没有 nation 的用户，计算不同地区的置信度
        List<UserPredictionResult> predictionResults = new ArrayList<>();
        for (User user : usersWithNoNation) {
            Map<String, Integer> regionScores = new HashMap<>();

            // 获取用户参与的所有项目
            List<Contri> userContributions = contriService.list(new QueryWrapper<Contri>().eq("user_id", user.getId()));
            Set<Long> userProjects = userContributions.stream().map(Contri::getRepoId).collect(Collectors.toSet());

            // 获取与用户共同参与项目的其他用户的地区分数
            for (Contri contri : userContributions) {
                Long repoId = contri.getRepoId();
                List<Contri> contributionsInRepo = contriService.list(new QueryWrapper<Contri>().eq("repo_id", repoId));

                for (Contri c : contributionsInRepo) {
                    if (!c.getUserId().equals(user.getId()) && userNations.containsKey(c.getUserId())) {
                        String region = userNations.get(c.getUserId());
                        regionScores.put(region, regionScores.getOrDefault(region, 0) + 1);
                    }
                }
            }

            // 获取用户所属组织的地区分数
            List<UserOrg> userOrgs = userOrgService.list(new QueryWrapper<UserOrg>().eq("user_id", user.getId()));
            for (UserOrg userOrg : userOrgs) {
                String orgLocation = orgLocations.get(userOrg.getOrgId());
                if (orgLocation != null && !orgLocation.equals("")) {
                    regionScores.put(orgLocation, regionScores.getOrDefault(orgLocation, 0) + 10);
                }
            }

            // 应用过滤条件，剔除分数小于 5 的地区
            regionScores.entrySet().removeIf(entry -> entry.getValue() < 5);

            // Step 4: 计算每个地区的置信度
            Map<String, Double> confidences = calculateSoftmax(regionScores);

            // Step 5: 查找置信度最高的地区
            Optional<Map.Entry<String, Double>> bestRegion = confidences.entrySet().stream()
                    .max(Comparator.comparing(Map.Entry::getValue));

            // Step 6: 如果最高置信度大于 0.5，记录该用户的预测结果
            bestRegion.ifPresent(entry -> {
                if (entry.getValue() > 0.5) {
                    user.setNation(entry.getKey());
                    user.setNationConfidence(entry.getValue());
                    userService.updateById(user);
                    predictionResults.add(new UserPredictionResult(user.getId(), entry.getValue(), user.getNation()));
                }
            });
        }

        // 给已有nation但nationConfidence为空的的用户置信度赋1
        List<User> usersWithNation = userService.list(new QueryWrapper<User>()
                .isNotNull("nation")
                .ne("nation", "")
                .isNull("nation_confidence")); // 查找已有nation但nationConfidence为空的用户

        for (User user : usersWithNation) {
            user.setNationConfidence(1.0);  // 给已有 nation 的用户置信度赋 1
            userService.updateById(user);  // 更新数据库
        }
        // 打印置信度统计信息
//        printConfidenceStats(predictionResults);
    }

    // 获取用户已知的 nation 数据且置信度为 1 的用户
    private Map<Long, String> getUserNations() {
        return userService.list(
                        new QueryWrapper<User>()
                                .isNotNull("nation")                // nation 不为 null
                                .ne("nation", "")                    // nation 不为空字符串
                                .eq("nation_confidence", 1.0)         // nationConfidence 为 1
                )
                .stream()
                .collect(Collectors.toMap(User::getId, User::getNation)); // 返回 userId -> nation 映射
    }


    // 获取组织的 location 数据
    private Map<Long, String> getOrgLocations() {
        return orgService.list().stream()
                .collect(Collectors.toMap(Org::getId, Org::getLocation));
    }

    // 计算 softmax 置信度 并乘以0.8
    private Map<String, Double> calculateSoftmax(Map<String, Integer> regionScores) {
        Map<String, Double> confidences = new HashMap<>();
        double sumExp = regionScores.values().stream().mapToDouble(Math::exp).sum();

        for (Map.Entry<String, Integer> entry : regionScores.entrySet()) {
            double confidence = 0.8 * Math.exp(entry.getValue()) / sumExp;
            confidences.put(entry.getKey(), confidence);
        }

        return confidences;
    }

    // 打印置信度的最大值、最小值、平均值和中位数
    private void printConfidenceStats(List<UserPredictionResult> results) {
        if (results.isEmpty()) {
            System.out.println("无可用预测数据");
            return;
        }
        System.out.println("猜测个数："+results.size());
        List<Double> confidences = results.stream().map(UserPredictionResult::getConfidence).sorted().collect(Collectors.toList());
        double minConfidence = confidences.get(0);
        double maxConfidence = confidences.get(confidences.size() - 1);
        double avgConfidence = confidences.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
        double medianConfidence = confidences.size() % 2 == 0
                ? (confidences.get(confidences.size() / 2 - 1) + confidences.get(confidences.size() / 2)) / 2
                : confidences.get(confidences.size() / 2);

        System.out.printf("置信度统计信息:\n最大值: %.2f, 最小值: %.2f, 平均值: %.2f, 中位数: %.2f%n", maxConfidence, minConfidence, avgConfidence, medianConfidence);
    }

    // 记录用户预测结果的类
    private static class UserPredictionResult {
        private final Long userId;
        private final double confidence;
        private String nation;

        public UserPredictionResult(Long userId, double confidence, String nation) {
            this.userId = userId;
            this.confidence = confidence;
            this.nation = nation;
        }

        public Long getUserId() {
            return userId;
        }

        public double getConfidence() {
            return confidence;
        }
    }
}
